<?php
//$HeadURL: http://instaforms.googlecode.com/svn/trunk/lib/implementation/impl.instaforms.class.php $
//$Revision: 20 $
//$Date: 2012-08-27 18:55:18 +0000 (Mon, 27 Aug 2012) $
//$Author: dev@arbrebinaire.com $
/**
 * An implementation example using files to store form definition and form answers 
 *
 * PHP version 5
 *
 * @package    com.arbrebinaire.instaforms
 * @author     Francois Hetu <dev@arbrebinaire.com>
 * @copyright  2012 Francois Hetu
 * @version    SVN: $Id: impl.instaforms.class.php 20 2012-08-27 18:55:18Z dev@arbrebinaire.com $
 */

require_once 'lib/bootstrap.php';

Zend_Loader::loadClass('Zend_Translate');
Zend_Loader::loadClass('Zend_Validate_Abstract');

class InstaformsSimpleFile implements InstaFormsController{

    private $formDefinitionDBFilename = 'form_definition_dbfile';
    private $formAnswersDBFilename = 'form_answers_dbfile';
    private $forms;

    public function __construct($lang = null){
        
        $this->formDefinitionDBFilename = dirname(__FILE__) . '/' . $this->formDefinitionDBFilename;
        
        $this->formAnswersDBFilename = dirname(__FILE__) . '/' . $this->formAnswersDBFilename;
        
        if(!file_exists($this->formDefinitionDBFilename)){
            $this->saveDataToFile($this->formDefinitionDBFilename, array());
        }
        
        if(!file_exists($this->formAnswersDBFilename)){
            $this->saveDataToFile($this->formAnswersDBFilename, array());
        }
        
        $this->forms = array();

        if($lang){
           $translator = new Zend_Translate(
                array(
                    'adapter' => 'array',
                    'content' => 'lib/resources/languages',
                    'locale'  => $lang,
                    'scan' => Zend_Translate::LOCALE_DIRECTORY
                )
           );
           Zend_Validate_Abstract::setDefaultTranslator($translator);
        }
    }

    private function sendResponse($str){
        echo $str;
    }
    
    private function getDataFromFile($fileDBName){
        $fileContent = file_get_contents($fileDBName);
        return $fileContent !== false ? json_decode($fileContent, true) : false;
    }
    private function saveDataToFile($fileDBName, $data){
        return file_put_contents($fileDBName, json_encode($data)) !== false;
    }
    private function removeForm($formId){
        $forms = $this->getDataFromFile($this->formDefinitionDBFilename);
        if($forms === false) return false;
        if(array_key_exists($formId, $forms)){
            unset($forms[$formId]);
            return $this->saveDataToFile($this->formDefinitionDBFilename, $forms);
        }
        return true;
    }
    private function getNextId(){
        $forms = $this->getDataFromFile($this->formDefinitionDBFilename);
        ksort($forms);
        $lastForm = array_pop($forms);
        if($lastForm){
            $form = new InstaformsFormDataObject($lastForm);
            return $form->getId() + 1;
        }else{
            return 1;
        }
    }
    public function getPostRequest($data){
        return $_POST;
    }
    public function isAjaxPostRequest($request){
        return isset($request) && isset($_SERVER['HTTP_X_REQUESTED_WITH']) && ( $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest');
    }
    public function sendData($data){
        $this->sendResponse($data);
    }
    public function sendEmptyResponse($data){
        $this->sendResponse('');
    }
    public function saveFormData(InstaformsFormDataObject $form){
        $success = true;
        if($form->isNew()){
            $formId = $this->getNextId();
        }else{
            $formId = $form->getId();
            $success = $this->removeForm($formId);
        }
        $forms = $this->getDataFromFile($this->formDefinitionDBFilename);
        $forms[$formId] = $form->toArray();
        return $this->saveDataToFile($this->formDefinitionDBFilename, $forms) && $success ? $formId : false;
    }
    public function getFormData($formId){
        $forms = $this->getDataFromFile($this->formDefinitionDBFilename);
        return $forms[$formId];
    }
    public function userHasAccessToForm($formId, $data){
        $formData = $this->getFormData($formId);
        return $formData['properties'][''];
    }
    public function userCanModifyForms($data){
        return true;
    }
    public function createForm($formId, $formAction){
        $formDefinition = $this->getFormData($formId);
        $formOptions = array(
        	'submit_value'             => $this->__('Submit'),
            'empty_select_option_text' => $this->__('Please select an option'),
        	'form_method'              => 'post',
            'form_name'                => 'instaform-form',
        	'form_id'                  => 'instaform-form',
            'form_action'              => $formAction,
            'form_description'         => $this->__('Please fill out the following form')
        );
        $formOptions = array(
        	'submit_value'             => $this->__('Submit'),
        	'empty_select_option_text' => $this->__('Please select an option')
        );
        $form = new InstaForm($formDefinition, $formOptions);
        $this->forms[$formId] = $form;
        return $form;
    }

    public function getForm($formId){
        return $this->forms[$formId];
    }

    public function renderForm($formId){
        echo $this->forms[$formId]->render();
    }

    private function removeAnswers($formId){
        $allAnswers = $this->getDataFromFile($this->formAnswersDBFilename);
        if($allAnswers === false) return false;
        if(array_key_exists($formId, $allAnswers)){
            unset($allAnswers[$formId]);
            return $this->saveDataToFile($this->formAnswersDBFilename, $allAnswers);
        }
        return true;
    }
    
    private function getQuestionSentence($formId, $questionId){
        $form = $this->getForm($formId);
        return $form->getElementSentence($questionId);
    
    }
    public function saveAnswer($formId, array $answer){
        
        $answerStorageArr = array();
        $answerValues = array();
        $answerPartFormat = array(
            'question_id' => '',
        	'sentence' => '',
            'answer_part' => ''
        );
        
        //We need to get the question, which may change over time
        foreach($answer as $questionId => $answerPart){
           $answerPartFormat = array(
              'question_id' => $questionId,
        	  'sentence' => $this->getQuestionSentence($formId, $questionId),
              'answer_part' => $answerPart
           );
           $answerValues[] = $answerPartFormat;
        }
        //Timestamping
        $timestamp = time();
        $answerStorageArr['timestamp'] = $timestamp;
        $answerStorageArr['values'] = $answerValues;
        //Storage
        $allAnswers = $this->getDataFromFile($this->formAnswersDBFilename);
        if(!array_key_exists($formId, $allAnswers)){
           $allAnswers[$formId] = array(); 
        }
        $allAnswers[$formId][] = $answerStorageArr;
        return $this->saveDataToFile($this->formAnswersDBFilename, $allAnswers);
    }
    
    public function getAnswersRowWidth($formId){
        $answers = $this->getAnswers($formId);
        $rowWidth = 0;
        foreach($answers as $answer){
            $answerWidth = count($answer['values']);
            $rowWidth = $rowWidth < $answerWidth ? $answerWidth : $rowWidth;
        }
        return $rowWidth;
    }
    
    public function buildNormalizedAnswerTableHeader($formId){
        $answers = $this->getAnswers($formId);
        $headers = array();
        $timestampElement = array(
            'question_id' => 'timestamp',
            'sentence'    => 'timestamp'
        );
        $headers[] = $timestampElement;
        $diffFunc = function($a, $b){
            return strcasecmp($a['question_id'], $b['question_id']);
        };
        //Looping through the answers to check for different questions
        foreach($answers as $answer){
            $prospectiveHeaders = array();
            $values = $answer['values'];
            foreach($values as $answerPart){
                $headerElement = array(
                    'question_id' => $answerPart['question_id'],
                    'sentence'    => $answerPart['sentence']
                );
                $prospectiveHeaders[] = $headerElement;
            }
            //Looking for headers not present in the array
            $diff = array_udiff($prospectiveHeaders, $headers, $diffFunc);
            //Merging the difference
            $headers = array_merge($headers, $diff);
        }
        return $headers;
    }
    
    public function getNormalizedAnswerTable($formId){
        $headers = $this->buildNormalizedAnswerTableHeader($formId);
        $answers = $this->getAnswers($formId);
        $rowWidth = count($headers);
        $table = array();
        //Building the headers row
        $row = array();
        foreach($headers as $header){
           $row[] = $header['sentence'];
        }
        $table[] = $row;
        
        //Building the rest of the table
        foreach($answers as $answer){
            $row = array();
            $timestamp = $answer['timestamp'];
            $values = $answer['values'];
            foreach($headers as $header){
                
                $questionId = $header['question_id'];
                
                $filter = function($el) use ($questionId){
                    return $questionId == $el['question_id'];
                };
                
                $found = array_filter($values, $filter);
                
                if($found){
                    $found = array_shift($found);
                    $question = $found['sentence'];
                    $answerPart = $found['answer_part'];
                    $answerPart = is_array($answerPart) ? implode(', ', $answerPart) : $answerPart;
                    $row[] = /*$question . '<br />'. */$answerPart;
                }elseif($questionId == 'timestamp'){
                    $row[] = $timestamp;
                }else{
                    $row[] = 'vide';
                }
            }
            $table[] = $row;
        }
        return $table;
    }
    
    public function getAnswers($formId){
        $answers = $this->getDataFromFile($this->formAnswersDBFilename);
        return $answers[$formId] ? $answers[$formId] : array();
    }

    public function countAnswers($formId){
        return count($this->getAnswers($formId));
    }
    
    private function getForms(){
        return $this->getDataFromFile($this->formDefinitionDBFilename);
    }
    
    public function renderFormSelect(){
        $forms = $this->getForms();
        foreach($forms as $form){
            
        }
    }
    
    public function formAcceptsAnswers($formId){
        $form = $this->getForm($formId);
        
        $show = true;
        
        //Property "Online" should be true, and validity dates checked
        $show = $show && $form->canBeShown();
        
        //Max num of answers should not have been reached
        $show = $show && $this->countAnswers($formId) < $form->getMaxNumberOfAnswers();
        
        return $show;
    }
    
    public function __($str, $lang = LANG, $dic = DIC){
        if($lang == 'en') return $str;
        $dic = unserialize($dic);
        if(array_key_exists($str, $dic)){
            $exp = $dic[$str];
            if(array_key_exists($lang, $exp)){
                return $exp[$lang];
            }else{
                return $str;
            }
        }else{
            return $str;
        }
    }

}